/**
 * ZHU framework. Copyright 2012-, all rights reserved.
 *
 * $Id: WebRequestContext.java 24 2012-08-17 07:21:26Z zhuxiaopeng $
 * $Revision: 24 $
 * $Date: 2012-08-17 15:21:26 +0800 (五, 2012-08-17) $
 * $Author: zhuxiaopeng $
 */
package zhu.framework.web;

import java.io.*;
import java.util.*;

import javax.faces.context.*;

import zhu.framework.service.*;

/**
 * <p>
 * </p>
 * 
 * @author $Author: zhuxiaopeng $
 * @version $Revision: 24 $ - $Date: 2012-08-17 15:21:26 +0800 (五, 2012-08-17) $
 */
public interface WebRequestContext {

	WebSessionContext getSessionContext();

	/**
	 * <p>
	 * ビジネス・ロジック呼び出しのために必要な<code>{@link ServiceRequestContext}</code>
	 * オブジェクトを取得する。 取得されるオブジェクトには現在のリクエストのコンテキスト情報が含まれているため、そのままビジネスロジック層に渡せばよい。
	 * </p>
	 * 
	 * @return ビジネス・ロジック呼び出しのために必要な<code>{@link ServiceRequestContext}</code>
	 *         オブジェクト
	 */
	ServiceRequestContext getServiceRequestContext();

	Object getAttribute(final String name);

	void setAttribute(final String name, final Object value);

	void removeAttribute(final String name);

	String getParameter(final String name);

	/**
	 * <p>
	 * このリクエストにおいて、ファイルのダウのロード等、non-JSFレスポンスを返したい場合をフレームワークに通知する。基本的な動作、意味づけは
	 * <code>{@link {@link javax.faces.context.FacesContext#responseComplete()}}</code>
	 * と同様。
	 * </p>
	 * <h4>JSF環境におけるNote</h4>
	 * <p>
	 * GlassFishのJSF 1.2環境においては、ファイル等のダウンロードを提供した後で
	 * <code>responseComplete()</code>
	 * をコールした場合、元のページで表示されているcommand要素をクリックすると再びダウンロードが行われてしまうという問題がある。
	 * このメソッドはこの問題を回避するための対処コードも実行する。 従って、暫定回避コードを記述する必要はない。
	 * </p>
	 * <p>
	 * この裏返しに、ピュアJSFにおける<code>responseComplete()</code>の呼び出しとは異なり、
	 * <code>responseComplete()</code>
	 * の前に下記のコードが実行されることによる副作用が発生する可能性がある（現時点では未確認）。
	 * </p>
	 * <blockquote><code>
	 *     final FacesContext facesContext = FacesContext.getCurrentInstance();<br/>
	 *     final StateManager stateManager = (StateManager)facesContext.getApplication().getStateManager();<br/>
	 *     stateManager.saveView(facesContext);<br/>
	 * </code></blockquote>
	 * 
	 * @see #getResponse()
	 * @see #getResponseWriter()
	 */
	void responseComplete();

	/**
	 * <p>
	 * このリクエストにおいて<code>{@link #responseComplete()}</code>が呼び出されたかどうかを判断する。
	 * </p>
	 * 
	 * @return 既に<code>{@link #responseComplete()}</code>が呼び出されていれば
	 *         <code>true</code>
	 * @see javax.faces.context.FacesContext#getResponseComplete()
	 */
	boolean isResponseCompleted();

	/**
	 * <p>
	 * 指定されたコンテキスト情報に従いクライアント側へのダウンロード・セッションを開始し、ダウンロード情報を送信するための
	 * <code>OutputStream</code>を取得する。
	 * 取得したStreamのライフサイクル管理は取得したクライアント・コードの責務となる。
	 * </p>
	 * <p>
	 * 引数に指定されたコンテキスト情報は、安全のため、このメソッド内部で{@link WebDownloadContext#setReadonly()
	 * 読み取り専用化}される。
	 * </p>
	 * 
	 * @param downloadContext
	 *            Downloadセッションのコンテキスト情報
	 * @return Downloadファイルを送信するための<code>OutputStream</code>
	 * @throws UnsupportedEncodingException
	 *             ファイル名のエンコーディングに失敗した場合
	 * @throws IOException
	 *             Streamの取得に失敗した場合
	 */
	OutputStream openDownloadStream(final WebDownloadContext downloadContext) throws UnsupportedEncodingException, IOException;

	/**
	 * <p>
	 * このリクエストの環境依存のResponseオブジェクトを取得する。 non-JSFレスポンスをレンダリングする等に利用する。
	 * Servlet環境では<code>{@link javax.servlet.http.HttpServletResponse }</code>
	 * のインスタンスが返される。 その他、動作は
	 * <code>{@link javax.faces.context.ExternalContext#getResponse()}</code>
	 * と同様。
	 * </p>
	 * <p>
	 * 単にファイルのダウンロード・セッションを開始したい場合は
	 * <code>{@link #openDownloadStream(WebDownloadContext)}</code>
	 * を利用することを強く推奨する。
	 * </p>
	 * 
	 * @return このリクエストの環境依存のResponseオブジェクト
	 * @see #responseComplete()
	 * @see #getResponseWriter()
	 * @see javax.faces.context.ExternalContext#getResponse()
	 */
	Object getResponse();

	/**
	 * <p>
	 * このリクエストの<code>{@link ResponseWriter}</code>オブジェクトを取得する。
	 * non-JSFレスポンスをレンダリングする等に利用する。 動作は
	 * <code>{@link javax.faces.context.FacesContext#getResponseWriter()}</code>
	 * と同様。
	 * </p>
	 * 
	 * @return
	 * @see #responseComplete()
	 * @see #getResponse()
	 */
	ResponseWriter getResponseWriter();

	/**
	 * <p>
	 * クライアント側に提示するメッセージを追加する。 Page Controller内でのメッセージ追加には、通常、
	 * <code>{@link #addMessage(WebMessage)}</code>を使用する。
	 * </p>
	 * 
	 * @param clientId
	 *            GUIコンポーネントのID（あれば）、または<code>null</code>
	 * @param message
	 *            メッセージオブジェクト
	 * @throws NullPointerException
	 *             <code>message==null</code>の場合
	 */
	void addMessage(final String clientId, final WebMessage message);

	/**
	 * <p>
	 * クライアント側に提示するメッセージを追加する。 メッセージは特定のGUIコンポーネントには関連づけられない。
	 * </p>
	 * 
	 * @param message
	 *            メッセージオブジェクト
	 * @throws NullPointerException
	 *             <code>message==null</code>の場合
	 */
	void addMessage(final WebMessage message);

	/**
	 * <p>
	 * Listに含まれるクライアント側に提示するメッセージを一括で追加する。 追加される順序は<code>List</code>
	 * に格納された順序に一致する。 Page Controller内でのメッセージ追加には、通常、
	 * <code>{@link #addMessages(List)}</code>を使用する。
	 * </p>
	 * 
	 * @param clientId
	 *            GUIコンポーネントのID（あれば）、または<code>null</code>
	 * @param messages
	 *            メッセージオブジェクトのList
	 * @throws NullPointerException
	 *             <code>messages==null</code>の場合、または、その中に<code>null</code>
	 *             が含まれる場合
	 */
	void addMessages(final String clientId, final List<WebMessage> messages);

	/**
	 * <p>
	 * Listに含まれるクライアント側に提示するメッセージを一括で追加する。 追加される順序は<code>List</code>
	 * に格納された順序に一致する。 メッセージは特定のGUIコンポーネントには関連づけられない。
	 * </p>
	 * 
	 * @param messages
	 *            メッセージオブジェクトのList
	 * @throws NullPointerException
	 *             <code>messages==null</code>の場合、または、その中に<code>null</code>
	 *             が含まれる場合
	 */
	void addMessages(final List<WebMessage> messages);
}
